import argparse
import re
import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox, ttk
from typing import List, Dict, Optional, Tuple
import os
import numpy as np  # 假设项目中已包含numpy


class PatchApplier:
    def __init__(self, context_lines: int = 3, debug: bool = False, 
                 use_code_structure: bool = False, 
                 use_signature: bool = False,
                 use_smart_position: bool = False,
                 force_apply: bool = False):
        self.context_lines = context_lines
        self.debug = debug
        self.use_code_structure = use_code_structure
        self.use_signature = use_signature
        self.use_smart_position = use_smart_position
        self.force_apply = force_apply

    def debug_print(self, message: str):
        if self.debug:
            print(f"[DEBUG] {message}")

    def read_file(self, filename: str) -> List[str]:
        """读取文件内容到行列表"""
        self.debug_print(f"读取文件: {filename}")
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                content = f.read().splitlines()
                self.debug_print(f"成功读取文件，共 {len(content)} 行")
                return content
        except FileNotFoundError:
            self.debug_print(f"错误：找不到文件 {filename}")
            return []
        except Exception as e:
            self.debug_print(f"读取文件时出错: {e}")
            return []

    def parse_patch(self, patch_content: List[str]) -> List[dict]:
        """解析补丁文件内容为补丁块列表，增强对非标准行号的容错"""
        self.debug_print(f"开始解析补丁文件，共 {len(patch_content)} 行")
        patches = []
        current_patch = None
        current_hunk = None
        hunk_lines = []
        state = "waiting_for_header"
        
        for i, line in enumerate(patch_content):
            line_type = self._categorize_line(line)
            self.debug_print(f"解析第 {i+1} 行: [{line_type}] {line[:70]}{'...' if len(line) > 70 else ''}")
            
            if state == "waiting_for_header":
                if line_type in ("diff_header", "file_header"):
                    self.debug_print(f"发现补丁头部: {line}")
                    current_patch = {'header': line, 'hunks': []}
                    patches.append(current_patch)
                    current_hunk = None
                    state = "in_patch"
                else:
                    self.debug_print("忽略非补丁头部行")
                    
            elif state == "in_patch":
                if line_type == "hunk_header":
                    self.debug_print(f"发现 hunk 头部: {line}")
                    if current_hunk is not None:
                        current_hunk['lines'] = hunk_lines
                        current_patch['hunks'].append(current_hunk)
                        self.debug_print(f"添加 hunk 到补丁，共 {len(current_patch['hunks'])} 个 hunks")
                        hunk_lines = []
                    
                    # 增强容错：允许行号为XXX的情况
                    try:
                        hunk_parts = line.split()
                        old_range = hunk_parts[1].strip('-')
                        new_range = hunk_parts[2].strip('+')
                        
                        # 处理XXX占位符
                        old_start = int(old_range.split(',')[0]) if old_range.split(',')[0].isdigit() else 0
                        old_count = int(old_range.split(',')[1]) if len(old_range.split(',')) > 1 and old_range.split(',')[1].isdigit() else 0
                        new_start = int(new_range.split(',')[0]) if new_range.split(',')[0].isdigit() else 0
                        new_count = int(new_range.split(',')[1]) if len(new_range.split(',')) > 1 and new_range.split(',')[1].isdigit() else 0
                        
                        current_hunk = {
                            'old_start': old_start,
                            'old_count': old_count,
                            'new_start': new_start,
                            'new_count': new_count,
                            'lines': []
                        }
                        hunk_lines = []
                        self.debug_print(f"解析 hunk 位置: 旧文件 {old_start},{old_count}, 新文件 {new_start},{new_count}")
                        state = "in_hunk"
                    except (IndexError, ValueError) as e:
                        self.debug_print(f"警告：无法解析hunk头信息: {line}, 错误: {str(e)}，使用智能定位")
                        current_hunk = {
                            'old_start': 0,
                            'old_count': 0,
                            'new_start': 0,
                            'new_count': 0,
                            'lines': []
                        }
                        hunk_lines = []
                        state = "in_hunk"
                elif line_type in ("diff_header", "file_header"):
                    self.debug_print(f"发现新的补丁头部，结束当前补丁处理: {line}")
                    if current_hunk is not None:
                        current_hunk['lines'] = hunk_lines
                        current_patch['hunks'].append(current_hunk)
                        self.debug_print(f"添加 hunk 到补丁，共 {len(current_patch['hunks'])} 个 hunks")
                        hunk_lines = []
                    current_patch = {'header': line, 'hunks': []}
                    patches.append(current_patch)
                    current_hunk = None
                    state = "in_patch"
                else:
                    self.debug_print("忽略非hunk头部行")
                    
            elif state == "in_hunk":
                if line_type == "hunk_header":
                    self.debug_print(f"发现新的 hunk 头部，结束当前hunk处理: {line}")
                    if current_hunk is not None:
                        current_hunk['lines'] = hunk_lines
                        current_patch['hunks'].append(current_hunk)
                        self.debug_print(f"添加 hunk 到补丁，共 {len(current_patch['hunks'])} 个 hunks")
                    
                    # 处理非标准行号
                    try:
                        hunk_parts = line.split()
                        old_range = hunk_parts[1].strip('-')
                        new_range = hunk_parts[2].strip('+')
                        
                        old_start = int(old_range.split(',')[0]) if old_range.split(',')[0].isdigit() else 0
                        old_count = int(old_range.split(',')[1]) if len(old_range.split(',')) > 1 and old_range.split(',')[1].isdigit() else 0
                        new_start = int(new_range.split(',')[0]) if new_range.split(',')[0].isdigit() else 0
                        new_count = int(new_range.split(',')[1]) if len(new_range.split(',')) > 1 and new_range.split(',')[1].isdigit() else 0
                        
                        current_hunk = {
                            'old_start': old_start,
                            'old_count': old_count,
                            'new_start': new_start,
                            'new_count': new_count,
                            'lines': []
                        }
                        hunk_lines = []
                        self.debug_print(f"解析 hunk 位置: 旧文件 {old_start},{old_count}, 新文件 {new_start},{new_count}")
                    except (IndexError, ValueError) as e:
                        self.debug_print(f"警告：无法解析hunk头信息: {line}, 错误: {str(e)}，使用智能定位")
                        current_hunk = {
                            'old_start': 0,
                            'old_count': 0,
                            'new_start': 0,
                            'new_count': 0,
                            'lines': []
                        }
                        hunk_lines = []
                elif line_type in ("diff_header", "file_header"):
                    self.debug_print(f"发现新的补丁头部，结束当前hunk处理: {line}")
                    if current_hunk is not None:
                        current_hunk['lines'] = hunk_lines
                        current_patch['hunks'].append(current_hunk)
                        self.debug_print(f"添加 hunk 到补丁，共 {len(current_patch['hunks'])} 个 hunks")
                    
                    current_patch = {'header': line, 'hunks': []}
                    patches.append(current_patch)
                    current_hunk = None
                    hunk_lines = []
                    state = "in_patch"
                else:
                    hunk_lines.append(line)
                    if line.startswith('+'):
                        self.debug_print(f"添加新增行到 hunk: {line}")
                    elif line.startswith('-'):
                        self.debug_print(f"添加删除行到 hunk: {line}")
                    else:
                        self.debug_print(f"添加上下文行到 hunk: {line}")

        # 添加最后一个hunk
        if current_patch is not None and current_hunk is not None:
            current_hunk['lines'] = hunk_lines
            current_patch['hunks'].append(current_hunk)
            self.debug_print(f"添加最后一个 hunk 到补丁，共 {len(current_patch['hunks'])} 个 hunks")

        self.debug_print(f"补丁解析完成，共解析出 {len(patches)} 个补丁")
        for i, patch in enumerate(patches):
            self.debug_print(f"补丁 {i+1}: {patch['header']}")
            self.debug_print(f"  包含 {len(patch['hunks'])} 个 hunks")
            for j, hunk in enumerate(patch['hunks']):
                self.debug_print(f"  Hunk {j+1}: 旧文件 {hunk['old_start']},{hunk['old_count']}, 新文件 {hunk['new_start']},{hunk['new_count']}")
                self.debug_print(f"    包含 {len(hunk['lines'])} 行")
                for k, line in enumerate(hunk['lines']):
                    if k < 3 or k >= len(hunk['lines']) - 3:
                        self.debug_print(f"    {line}")
                    elif k == 3:
                        self.debug_print("    ...")

        return patches

    def _categorize_line(self, line: str) -> str:
        """对补丁文件中的行进行分类"""
        if line.startswith('diff '):
            return 'diff_header'
        elif line.startswith('--- ') or line.startswith('+++ '):
            return 'file_header'
        elif line.startswith('@@ '):
            return 'hunk_header'
        else:
            return 'content'

    def find_hunk_position(self, target: List[str], hunk: dict) -> Optional[int]:
        """使用上下文匹配找到hunk在目标文件中的位置，增强错误处理"""
        self.debug_print(f"寻找 hunk 位置: 旧文件 {hunk['old_start']},{hunk['old_count']}")
        
        # 提取所有上下文信息（包括新增行）
        context_lines = []
        for line in hunk['lines']:
            # 跳过hunk头部，保留所有内容（包括空行和注释）
            if not line.startswith('@@'):
                clean_line = line[1:] if line.startswith((' ', '-', '+')) else line
                context_lines.append(clean_line)
        
        self.debug_print(f"hunk 原始上下文信息: {len(context_lines)}行")
        
        # 尝试多种定位方法（优先级排序）
        strategies = []
        
        if self.use_code_structure:
            strategies.append(lambda: self._locate_by_code_structure(target, context_lines))
            
        if self.use_signature:
            strategies.append(lambda: self._locate_by_signature(target, context_lines))
            
        # 始终使用上下文匹配
        strategies.append(lambda: self._enhanced_context_match(target, context_lines))
        
        if self.use_smart_position:
            strategies.append(lambda: self.find_smart_position(target, [
                line[1:] for line in hunk['lines'] 
                if line.startswith('+') and line[1:].strip()
            ]))
        
        # 添加最终回退策略
        strategies.append(lambda: len(target) if self.force_apply else None)
        
        # 执行策略链
        for strategy in strategies:
            position = strategy()
            if position is not None:
                self.debug_print(f"定位策略成功，位置: {position}")
                return position
                
        self.debug_print("所有定位策略失败")
        return None
    
    def _locate_by_signature(self, target: List[str], context: List[str]) -> Optional[int]:
        """通过函数签名定位"""
        # 扩展匹配模式
        signature_patterns = [
            r'set_title\(', r'set_xlabel\(', r'set_ylabel\(', r'grid\(', r'legend\(',
            r'set_xticks\(', r'text\(', r'tight_layout\(', r'draw\(\)', r'plot\(',
            r'scatter\(', r'bar\(', r'hist\(', r'subplots\(', r'subplot\(', 
            r'figure\(', r'savefig\(', r'show\(\)', r'xlim\(', r'ylim\('
        ]
        
        for i, line in enumerate(context):
            for pattern in signature_patterns:
                if re.search(pattern, line):
                    self.debug_print(f"发现签名模式: {pattern} 在上下文行 {i}")
                    for j, target_line in enumerate(target):
                        if re.search(pattern, target_line):
                            self.debug_print(f"在目标文件中找到匹配签名: 行 {j} - {target_line[:60]}")
                            return j
        return None
    
    def _enhanced_context_match(self, target: List[str], context: List[str]) -> Optional[int]:
        """增强版上下文匹配，实现严格原本文本逐行匹配（不过滤空行/注释）"""
        if not context:
            return None
            
        self.debug_print(f"使用原始文本进行逐行精确匹配: {len(context)}行")
        
        \
        key_lines = context.copy()
        
        possible_positions = list(range(len(target)))
        
        for i, key_line in enumerate(key_lines):
            if not possible_positions:
                self.debug_print(f"行 {i} 匹配后没有可能的位置，匹配失败")
                return None
                
            self.debug_print(f"使用第 {i+1} 行原始内容 '{key_line[:30]}...' 进行精确匹配")
            
            \
            new_positions = []
            for pos in possible_positions:
                if pos + i >= len(target):
                    continue  \
                    
                target_line = target[pos + i] if pos + i < len(target) else ""
                if target_line == key_line:
                    new_positions.append(pos)
        
            possible_positions = new_positions
            
            if len(possible_positions) == 0:
                self.debug_print(f"行 {i+1} 没有找到精确匹配，匹配失败")
                return None
            elif len(possible_positions) == 1:
                self.debug_print(f"找到唯一精确匹配位置: {possible_positions[0]}")
                return possible_positions[0]
            else:
                self.debug_print(f"行 {i+1} 找到 {len(possible_positions)} 个可能位置，继续用下一行匹配")
        
        \
        if possible_positions:
            best_pos = possible_positions[0]
            self.debug_print(f"精确匹配完成，选择第一个可能位置: {best_pos}")
            return best_pos
            
        return None

    def _locate_by_code_structure(self, target: List[str], context: List[str]) -> Optional[int]:
        """基于代码结构特征定位"""
        \
        for line in context:
            if 'def ' in line and '(' in line:
                method_name = line.split('def ')[1].split('(')[0].strip()
                self.debug_print(f"在上下文中发现方法定义: {method_name}")
                for i, line in enumerate(target):
                    if f"def {method_name}(" in line:
                        self.debug_print(f"在目标文件中找到方法: {method_name} 在行 {i}")
                        return i
        
        \
        for line in context:
            if 'class ' in line and '(' in line and ':' in line:
                class_name = line.split('class ')[1].split('(')[0].strip()
                self.debug_print(f"在上下文中发现类定义: {class_name}")
                for i, line in enumerate(target):
                    if f"class {class_name}(" in line:
                        self.debug_print(f"在目标文件中找到类: {class_name} 在行 {i}")
                        return i
                        
        return None
    
    def _detect_method_name(self, context: List[str]) -> Optional[str]:
        """从上下文中检测方法名"""
        \
        for line in context:
            if 'def ' in line and '(' in line:
                parts = line.split('def ')
                if len(parts) > 1:
                    method_part = parts[1].split('(')[0].strip()
                    if method_part:
                        return method_part
        return None

    def _extract_method_name(self, context_lines: List[str]) -> Optional[str]:
        """从上下文行中提取方法名，增强鲁棒性"""
        for line in context_lines:
            if line.strip().startswith('def '):
                try:
                    return line.strip().split()[1].split('(')[0]
                except IndexError:
                    continue
        return None

    def _find_method_position(self, target: List[str], method_name: str) -> Optional[int]:
        """查找方法定义的位置，处理长文件情况"""
        method_pattern = re.compile(rf'^\s*def\s+{method_name}\s*\(')
        for i, line in enumerate(target):
            if method_pattern.match(line):
                return i
        return None

    def _find_hunk_in_method(self, target: List[str], hunk: dict, context_lines: List[str], method_start: int) -> Optional[int]:
        """在方法内部查找hunk的位置，增强索引安全检查"""
        if method_start >= len(target):
            self.debug_print("警告：方法起始行超出文件范围")
            return None
            
        method_indent = len(target[method_start]) - len(target[method_start].lstrip())
        method_end = method_start + 1
        
        for i in range(method_start + 1, len(target)):
            if i >= len(target):
                break
            line_indent = len(target[i]) - len(target[i].lstrip())
            if line_indent <= method_indent and target[i].strip():
                method_end = i
                break
        
        best_position = None
        best_score = 0
        for i in range(method_start + 1, min(method_end, len(target))):
            if i >= len(target):
                break
            score = self.verify_context_with_score(target, context_lines, i)
            if score > best_score:
                best_score = score
                best_position = i
        
        if best_position is not None and best_score > 0.3:
            self.debug_print(f"在方法内部找到匹配位置: {best_position}, 分数: {best_score:.2f}")
            return best_position
            
        self.debug_print(f"在方法末尾位置 {max(method_start + 1, min(method_end - 1, len(target) - 1))} 插入")
        return max(method_start + 1, min(method_end - 1, len(target) - 1))

    def _find_class_start(self, target: List[str], context_lines: List[str]) -> Optional[int]:
        """查找上下文行所属的类定义起始位置，处理长文件情况"""
        class_name = self._extract_class_name(context_lines)
        if not class_name:
            return None
            
        class_pattern = re.compile(rf'^\s*class\s+{class_name}\s*(\([^)]*\))?\s*:')
        for i, line in enumerate(target):
            if class_pattern.match(line):
                return i
        return None

    def _extract_class_name(self, context_lines: List[str]) -> Optional[str]:
        """从上下文行中提取类名，增强鲁棒性"""
        for line in context_lines:
            if line.strip().startswith('class '):
                try:
                    return line.strip().split()[1].split('(')[0]
                except IndexError:
                    continue
        return None

    def _find_best_context_match(self, target: List[str], context: List[str]) -> Optional[int]:
        """使用传统上下文匹配找到最佳位置，增强索引安全"""
        best_position = None
        best_score = 0
        
        for i in range(len(context)):
            line = context[i]
            if not line.strip():
                continue  # 空行可能影响匹配，此处仅跳过全空行
                
            anchor_line = re.escape(line)
            pattern = re.compile(rf'^{anchor_line}$', re.MULTILINE)
            target_text = '\n'.join(target)
            for match in pattern.finditer(target_text):
                line_num = target_text.count('\n', 0, match.start())
                # 增加索引安全检查
                if line_num - i < 0 or line_num - i >= len(target):
                    continue
                score = self.verify_context_with_score(target, context, line_num - i)
                if score > best_score:
                    best_score = score
                    best_position = line_num - i

        if best_position is not None and best_score > 0.5:
            self.debug_print(f"最佳匹配位置: {best_position}，匹配分数: {best_score:.2f}")
            return best_position
            
        return None

    def _force_find_position(self, target: List[str], hunk: dict, added_lines: List[str]) -> Optional[int]:
        """强制定位：当上下文行无效时，根据新增内容类型定位，增强索引安全"""
        if not added_lines:
            return len(target)
            
        first_line = added_lines[0].strip()
        if first_line.startswith(('def ', 'class ')):
            return self.find_smart_position(target, added_lines)
            
        # 查找可能的类或方法
        class_start = self._find_class_start(target, added_lines)
        if class_start is not None:
            return min(class_start + 1, len(target) - 1)
            
        method_name = self._extract_method_name(added_lines)
        if method_name:
            method_pos = self._find_method_position(target, method_name)
            if method_pos is not None:
                return min(method_pos + 1, len(target) - 1)
                
        return len(target)

    def find_smart_position(self, target: List[str], added_lines: List[str]) -> Optional[int]:
        """智能定位新增内容的位置，增强索引安全"""
        if not added_lines:
            return None
            
        first_line = added_lines[0].strip()
        
        # 类成员方法定位增强
        if first_line.startswith('def ') and 'self' in first_line:
            method_name = first_line.split('def ')[1].split('(')[0].strip()
            self.debug_print(f"查找类成员方法: {method_name}")
            
            class_context = False
            current_class = None
            
            for i, line in enumerate(target):
                # 检测类定义
                if line.strip().startswith('class '):
                    class_name = line.split('class ')[1].split('(')[0].split(':')[0].strip()
                    current_class = class_name
                    class_context = True
                    self.debug_print(f"进入类 {class_name}")
                
                # 在类上下文中查找方法
                if class_context and line.strip().startswith(f'def {method_name}('):
                    self.debug_print(f"找到方法定义位置: {i}")
                    return i + 1
                    
                # 类结束检测
                if class_context and line.strip() == '' and i > 0:
                    next_line = target[i+1] if i+1 < len(target) else ''
                    if not next_line.startswith(' ') and not next_line.startswith('\t'):
                        self.debug_print(f"类 {current_class} 结束位置: {i}")
                        return i
        
        # 原有逻辑保持不变
        if first_line.startswith(('def ', 'class ')):
            indent_level = len(added_lines[0]) - len(added_lines[0].lstrip())
            self.debug_print(f"查找类定义，方法缩进: {indent_level}")
            
            class_start = None
            class_indent = -1
            for i, line in enumerate(target):
                if i >= len(target):
                    break
                if line.strip().startswith('class ') and (class_indent < 0 or (len(line) - len(line.lstrip())) < indent_level):
                    class_start = i
                    class_indent = len(line) - len(line.lstrip())
                    self.debug_print(f"找到类定义: {line.strip()}, 缩进: {class_indent}, 行号: {i}")
                    
                    for j in range(i + 1, len(target)):
                        if j >= len(target):
                            break
                        line_indent = len(target[j]) - len(target[j].lstrip())
                        if line_indent <= class_indent and target[j].strip():
                            self.debug_print(f"类结束位置: {j}, 在位置 {j-1} 插入")
                            return max(0, j - 1)
                    return min(i + 1, len(target) - 1)
            
            self.debug_print("未找到合适的类定义，在文件末尾插入")
            return len(target)
            
        elif first_line.startswith('    ') or first_line.startswith('\t'):
            indent_level = len(added_lines[0]) - len(added_lines[0].lstrip())
            self.debug_print(f"查找方法内部位置，缩进: {indent_level}")
            
            method_pattern = re.compile(r'^\s*def\s+(\w+)\s*\(')
            for i in range(len(target) - 1, -1, -1):
                if i < 0 or i >= len(target):
                    continue
                if method_pattern.match(target[i]):
                    method_indent = len(target[i]) - len(target[i].lstrip())
                    if method_indent < indent_level:
                        #self.debug_print\)



                        self.debug_print(f"找到可能的方法定义在位置 {i}")
                        for j in range(i + 1, len(target)):
                            if j >= len(target):
                                break
                            line_indent = len(target[j]) - len(target[j].lstrip())
                            if line_indent <= method_indent and target[j].strip():
                                break  # 方法结束
                            
                            if line_indent == indent_level:
                                self.debug_print(f"在位置 {j} 前插入")
                                return max(0, j)
                        
                        self.debug_print(f"在方法末尾位置 {j-1} 插入")
                        return max(0, j - 1)
            
        self.debug_print("未知类型的新增内容，在文件末尾插入")
        return len(target)

    def verify_context_with_score(self, target: List[str], context: List[str], start_line: int) -> float:
        """严格原本文本匹配的分数验证（仅完全匹配计分）"""
        match_count = 0
        total_count = min(len(context), len(target) - start_line)
        
        for i in range(total_count):
            patch_line = context[i]
            target_line = target[start_line + i] if start_line + i < len(target) else ""
            if target_line == patch_line:
                match_count += 1
        
        return match_count / total_count if total_count > 0 else 0

    def apply_hunk(self, target: List[str], hunk: dict, position: int) -> List[str]:
        """应用单个hunk到目标文件，增强索引安全检查"""
        self.debug_print(f"应用 hunk 到位置 {position}")
        new_content = []
        i = 0

        # 确保position在有效范围内
        position = max(0, min(position, len(target)))

        while i < position and i < len(target):
            new_content.append(target[i])
            i += 1

        for line in hunk['lines']:
            if line.startswith('+'):
                new_content.append(line[1:])
                self.debug_print(f"  添加行: {line[1:]}")
            elif line.startswith('-'):
                if i < len(target):
                    i += 1
                    self.debug_print(f"  删除行: {target[i-1]}")
            else:
                if i < len(target):
                    new_content.append(target[i])
                    self.debug_print(f"  保留行: {target[i]}")
                    i += 1

        while i < len(target):
            new_content.append(target[i])
            i += 1

        self.debug_print(f"hunk 应用完成，新内容长度: {len(new_content)}")
        return new_content

    def apply_patch(self, target: List[str], patch: dict) -> List[str]:
        """应用单个补丁到目标文件，增强错误处理"""
        self.debug_print(f"补丁头部: {patch['header']}")
        for i, hunk in enumerate(patch['hunks']):
            self.debug_print(f"\n处理 Hunk {i+1}:")
            self.debug_print(f"  旧范围: {hunk['old_start']}-{hunk['old_start']+hunk['old_count']}")
            self.debug_print(f"  新范围: {hunk['new_start']}-{hunk['new_start']+hunk['new_count']}")
            self.debug_print("  Hunk 内容:")
            for line in hunk['lines'][:5]:
                self.debug_print(f"    {line}")
            if len(hunk['lines']) > 5:
                self.debug_print(f"    ...({len(hunk['lines'])-5} more lines)")
        
        self.debug_print(f"开始应用补丁，包含 {len(patch['hunks'])} 个 hunks")
        new_content = target.copy()
        for i, hunk in enumerate(patch['hunks']):
            self.debug_print(f"处理 hunk {i+1}/{len(patch['hunks'])}")
            try:
                position = self.find_hunk_position(new_content, hunk)
                if position is not None:
                    new_content = self.apply_hunk(new_content, hunk, position)
                    print(f"成功应用hunk {i+1}，位置：{position}")
                else:
                    if self.force_apply:
                        print(f"警告：无法找到hunk {i+1}的匹配位置，强制应用到文件末尾")
                        new_content = self.apply_hunk(new_content, hunk, len(new_content))
                    else:
                        print(f"警告：无法找到hunk {i+1}的匹配位置，跳过")
                        self.debug_print(f"hunk {i+1} 内容:")
                        for line in hunk['lines']:
                            self.debug_print(f"  {line}")
            except Exception as e:
                print(f"应用hunk {i+1} 时出错: {str(e)}")
                self.debug_print(f"hunk {i+1} 处理错误: {str(e)}")

        self.debug_print(f"补丁应用完成，原始长度: {len(target)}, 新长度: {len(new_content)}")
        return new_content

    def write_file(self, filename: str, content: List[str]) -> None:
        """将内容写入文件"""
        self.debug_print(f"写入文件: {filename}, 内容行数: {len(content)}")
        with open(filename, 'w', encoding='utf-8') as f:
            f.write('\n'.join(content) + '\n')

    def compare_files(self, original: List[str], modified: List[str]) -> List[dict]:
        """比较两个文件内容，返回差异列表"""
        self.debug_print(f"比较文件: 原始文件 {len(original)} 行, 修改后文件 {len(modified)} 行")
        from difflib import ndiff
        diffs = []
        for i, line in enumerate(ndiff(original, modified)):
            if line.startswith('+'):
                diffs.append({'type': 'add', 'line': i, 'content': line[2:]})
            elif line.startswith('-'):
                diffs.append({'type': 'remove', 'line': i, 'content': line[2:]})
        self.debug_print(f"文件比较完成，发现 {len(diffs)} 处差异")
        return diffs

    def generate_output_filename(self, original_filename: str) -> str:
        """生成默认输出文件名（原始名加_new字段）"""
        dirname = os.path.dirname(original_filename)
        basename = os.path.basename(original_filename)
        name, ext = os.path.splitext(basename)
        output_filename = os.path.join(dirname, f"{name}_new{ext}")
        self.debug_print(f"生成输出文件名: {output_filename}")
        return output_filename

class PatchApplierGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("智能补丁应用工具（严格文本匹配）")
        self.root.geometry("1000x700")
        self.root.minsize(800, 600)
        self.create_widgets()
        self.create_layout()
        
    def create_widgets(self):
        # 文件选择区域
        self.original_file_frame = ttk.LabelFrame(self.root, text="原始文件")
        self.original_file_path = tk.StringVar()
        self.original_file_entry = ttk.Entry(self.original_file_frame, textvariable=self.original_file_path, width=60)
        self.original_file_button = ttk.Button(self.original_file_frame, text="浏览...", command=self.browse_original_file)
        
        self.patch_file_frame = ttk.LabelFrame(self.root, text="补丁文件")
        self.patch_file_path = tk.StringVar()
        self.patch_file_entry = ttk.Entry(self.patch_file_frame, textvariable=self.patch_file_path, width=60)
        self.patch_file_button = ttk.Button(self.patch_file_frame, text="浏览...", command=self.browse_patch_file)
        
        self.output_file_frame = ttk.LabelFrame(self.root, text="输出文件")
        self.output_file_path = tk.StringVar()
        self.output_file_entry = ttk.Entry(self.output_file_frame, textvariable=self.output_file_path, width=60)
        self.output_file_button = ttk.Button(self.output_file_frame, text="浏览...", command=self.browse_output_file)
        
        # 定位策略选择区域
        self.strategy_frame = ttk.LabelFrame(self.root, text="定位策略")
        self.use_code_structure_var = tk.BooleanVar(value=False)
        self.use_code_structure_check = ttk.Checkbutton(
            self.strategy_frame, 
            text="使用代码结构定位（函数/类）", 
            variable=self.use_code_structure_var
        )
        
        self.use_signature_var = tk.BooleanVar(value=False)
        self.use_signature_check = ttk.Checkbutton(
            self.strategy_frame, 
            text="使用函数签名匹配", 
            variable=self.use_signature_var
        )
        
        self.use_smart_position_var = tk.BooleanVar(value=False)
        self.use_smart_position_check = ttk.Checkbutton(
            self.strategy_frame, 
            text="使用智能位置推断", 
            variable=self.use_smart_position_var
        )
        
        # 默认启用上下文匹配（严格文本匹配）
        self.use_context_var = tk.BooleanVar(value=True)
        self.use_context_check = ttk.Checkbutton(
            self.strategy_frame, 
            text="使用严格文本匹配（默认启用）", 
            variable=self.use_context_var,
            state="disabled"  # 禁用，因为始终启用
        )
        
        self.force_apply_var = tk.BooleanVar(value=False)
        self.force_apply_check = ttk.Checkbutton(
            self.strategy_frame, 
            text="强制应用（在文件末尾）", 
            variable=self.force_apply_var
        )
        
        # 调试选项
        self.debug_frame = ttk.LabelFrame(self.root, text="调试选项")
        self.debug_var = tk.BooleanVar(value=False)
        self.debug_check = ttk.Checkbutton(
            self.debug_frame, 
            text="启用调试输出", 
            variable=self.debug_var
        )
        
        # 按钮区域
        self.button_frame = ttk.Frame(self.root)
        self.apply_button = ttk.Button(self.button_frame, text="应用补丁", command=self.apply_patch)
        self.compare_button = ttk.Button(self.button_frame, text="比较文件", command=self.compare_files, state="disabled")
        self.save_button = ttk.Button(self.button_frame, text="保存结果", command=self.save_result, state="disabled")
        
        # 结果显示区域
        self.result_frame = ttk.LabelFrame(self.root, text="处理结果")
        self.result_text = scrolledtext.ScrolledText(self.result_frame, wrap=tk.WORD, width=80, height=20)
        
        # 差异显示区域
        self.diff_frame = ttk.LabelFrame(self.root, text="文件差异")
        self.diff_text = scrolledtext.ScrolledText(self.diff_frame, wrap=tk.WORD, width=80, height=10)
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        self.status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        
    def create_layout(self):
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        for i in range(8):
            self.root.rowconfigure(i, weight=1)
        
        # 放置文件选择区域
        self.original_file_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew")
        self.original_file_entry.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
        self.original_file_button.grid(row=0, column=1, padx=5, pady=5)
        
        self.patch_file_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew")
        self.patch_file_entry.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
        self.patch_file_button.grid(row=0, column=1, padx=5, pady=5)
        
        self.output_file_frame.grid(row=2, column=0, padx=10, pady=5, sticky="ew")
        self.output_file_entry.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
        self.output_file_button.grid(row=0, column=1, padx=5, pady=5)
        
        # 放置定位策略选择区域
        self.strategy_frame.grid(row=3, column=0, padx=10, pady=5, sticky="ew")
        self.use_code_structure_check.grid(row=0, column=0, padx=5, pady=2, sticky="w")
        self.use_signature_check.grid(row=1, column=0, padx=5, pady=2, sticky="w")
        self.use_smart_position_check.grid(row=2, column=0, padx=5, pady=2, sticky="w")
        self.use_context_check.grid(row=3, column=0, padx=5, pady=2, sticky="w")
        self.force_apply_check.grid(row=4, column=0, padx=5, pady=2, sticky="w")
        
        # 放置调试选项
        self.debug_frame.grid(row=4, column=0, padx=10, pady=5, sticky="ew")
        self.debug_check.grid(row=0, column=0, padx=5, pady=2, sticky="w")
        
        # 放置按钮区域
        self.button_frame.grid(row=5, column=0, padx=10, pady=5, sticky="ew")
        self.apply_button.grid(row=0, column=0, padx=5, pady=5)
        self.compare_button.grid(row=0, column=1, padx=5, pady=5)
        self.save_button.grid(row=0, column=2, padx=5, pady=5)
        
        # 放置结果显示区域
        self.result_frame.grid(row=6, column=0, padx=10, pady=5, sticky="nsew")
        self.result_text.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        
        # 放置差异显示区域
        self.diff_frame.grid(row=7, column=0, padx=10, pady=5, sticky="nsew")
        self.diff_text.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        
        # 放置状态栏
        self.status_bar.grid(row=8, column=0, sticky="ew")
        
        # 配置结果和差异文本区域的权重
        self.result_frame.rowconfigure(0, weight=1)
        self.result_frame.columnconfigure(0, weight=1)
        self.diff_frame.rowconfigure(0, weight=1)
        self.diff_frame.columnconfigure(0, weight=1)
        
    def browse_original_file(self):
        filename = filedialog.askopenfilename(
            title="选择原始文件",
            filetypes=[("Python文件", "*.py"), ("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if filename:
            self.original_file_path.set(filename)
            self.generate_output_filename()
            
    def browse_patch_file(self):
        filename = filedialog.askopenfilename(
            title="选择补丁文件",
            filetypes=[("补丁文件", "*.patch"), ("diff文件", "*.diff"), ("所有文件", "*.*")]
        )
        if filename:
            self.patch_file_path.set(filename)
            
    def browse_output_file(self):
        filename = filedialog.asksaveasfilename(
            title="保存输出文件",
            defaultextension=".py",
            filetypes=[("Python文件", "*.py"), ("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if filename:
            self.output_file_path.set(filename)
            
    def generate_output_filename(self):
        """根据原始文件名生成默认输出文件名"""
        original = self.original_file_path.get()
        if original:
            dirname = os.path.dirname(original)
            basename = os.path.basename(original)
            name, ext = os.path.splitext(basename)
            output = os.path.join(dirname, f"{name}_patched{ext}")
            self.output_file_path.set(output)
            
    def apply_patch(self):
        """应用补丁到原始文件"""
        original_file = self.original_file_path.get()
        patch_file = self.patch_file_path.get()
        output_file = self.output_file_path.get()
        
        if not original_file or not patch_file or not output_file:
            messagebox.showerror("错误", "请选择原始文件、补丁文件和输出文件")
            return
            
        try:
            # 清空结果和差异显示区域
            self.result_text.delete(1.0, tk.END)
            self.diff_text.delete(1.0, tk.END)
            
            # 创建PatchApplier实例
            applier = PatchApplier(
                debug=self.debug_var.get(),
                use_code_structure=self.use_code_structure_var.get(),
                use_signature=self.use_signature_var.get(),
                use_smart_position=self.use_smart_position_var.get(),
                force_apply=self.force_apply_var.get()
            )
            
            # 读取原始文件和补丁文件
            self.status_var.set("正在读取文件...")
            self.root.update()
            
            original_content = applier.read_file(original_file)
            if not original_content:
                messagebox.showerror("错误", f"无法读取原始文件: {original_file}")
                self.status_var.set("就绪")
                return
                
            patch_content = applier.read_file(patch_file)
            if not patch_content:
                messagebox.showerror("错误", f"无法读取补丁文件: {patch_file}")
                self.status_var.set("就绪")
                return
                
            # 解析补丁文件
            self.status_var.set("正在解析补丁文件...")
            self.root.update()
            
            patches = applier.parse_patch(patch_content)
            if not patches:
                messagebox.showerror("错误", "无法解析补丁文件，格式可能不正确")
                self.status_var.set("就绪")
                return
                
            # 应用补丁
            self.status_var.set("正在应用补丁...")
            self.root.update()
            
            modified_content = original_content.copy()
            for patch in patches:
                modified_content = applier.apply_patch(modified_content, patch)
                
            # 保存结果
            self.status_var.set("正在保存结果...")
            self.root.update()
            
            applier.write_file(output_file, modified_content)
            
            # 显示结果
            self.result_text.insert(tk.END, f"补丁已成功应用到文件:\n{output_file}\n\n")
            self.result_text.insert(tk.END, "处理摘要:\n")
            self.result_text.insert(tk.END, f"原始文件: {len(original_content)} 行\n")
            self.result_text.insert(tk.END, f"修改后文件: {len(modified_content)} 行\n")
            
            # 比较文件
            diffs = applier.compare_files(original_content, modified_content)
            self.diff_text.insert(tk.END, f"文件差异 ({len(diffs)} 处):\n")
            for diff in diffs[:20]:  # 只显示前20个差异
                if diff['type'] == 'add':
                    self.diff_text.insert(tk.END, f"+ {diff['content']}\n", "add")
                else:
                    self.diff_text.insert(tk.END, f"- {diff['content']}\n", "remove")
            
            if len(diffs) > 20:
                self.diff_text.insert(tk.END, f"... 还有 {len(diffs)-20} 处差异未显示\n")
            
            # 启用比较和保存按钮
            self.compare_button.config(state="normal")
            self.save_button.config(state="normal")
            
            self.status_var.set("完成")
            messagebox.showinfo("成功", f"补丁已成功应用到文件:\n{output_file}")
            
        except Exception as e:
            self.status_var.set("错误")
            error_msg = f"应用补丁时出错: {str(e)}"
            self.result_text.insert(tk.END, error_msg + "\n")
            messagebox.showerror("错误", error_msg)
            if self.debug_var.get():
                import traceback
                self.result_text.insert(tk.END, traceback.format_exc())
                
    def compare_files(self):
        """比较原始文件和修改后的文件"""
        original_file = self.original_file_path.get()
        output_file = self.output_file_path.get()
        
        if not original_file or not output_file:
            messagebox.showerror("错误", "请选择原始文件和输出文件")
            return
            
        try:
            # 创建PatchApplier实例
            applier = PatchApplier(debug=self.debug_var.get())
            
            # 读取文件内容
            original_content = applier.read_file(original_file)
            modified_content = applier.read_file(output_file)
            
            if not original_content or not modified_content:
                messagebox.showerror("错误", "无法读取文件内容")
                return
                
            # 比较文件
            diffs = applier.compare_files(original_content, modified_content)
            
            # 清空差异显示区域并显示结果
            self.diff_text.delete(1.0, tk.END)
            self.diff_text.insert(tk.END, f"文件差异 ({len(diffs)} 处):\n")
            
            # 配置标签以显示不同颜色的差异
            self.diff_text.tag_config("add", foreground="green")
            self.diff_text.tag_config("remove", foreground="red")
            
            for diff in diffs:
                if diff['type'] == 'add':
                    self.diff_text.insert(tk.END, f"+ {diff['content']}\n", "add")
                else:
                    self.diff_text.insert(tk.END, f"- {diff['content']}\n", "remove")
            
            messagebox.showinfo("比较完成", f"文件比较完成，发现 {len(diffs)} 处差异")
            
        except Exception as e:
            error_msg = f"比较文件时出错: {str(e)}"
            self.diff_text.delete(1.0, tk.END)
            self.diff_text.insert(tk.END, error_msg)
            messagebox.showerror("错误", error_msg)
            
    def save_result(self):
        """保存结果文本到文件"""
        output_file = self.output_file_path.get()
        if not output_file:
            messagebox.showerror("错误", "请先应用补丁或选择输出文件")
            return
            
        try:
            content = self.result_text.get(1.0, tk.END)
            with open(output_file + ".log", 'w', encoding='utf-8') as f:
                f.write(content)
                
            messagebox.showinfo("成功", f"结果已保存到文件:\n{output_file}.log")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存结果时出错: {str(e)}")

def main():
    parser = argparse.ArgumentParser(description="智能补丁应用工具")
    parser.add_argument("-o", "--original", help="原始文件路径")
    parser.add_argument("-p", "--patch", help="补丁文件路径")
    parser.add_argument("-d", "--output", help="输出文件路径")
    parser.add_argument("--debug", action="store_true", help="启用调试输出")
    parser.add_argument("--code-structure", action="store_true", help="使用代码结构定位")
    parser.add_argument("--signature", action="store_true", help="使用函数签名匹配")
    parser.add_argument("--smart-position", action="store_true", help="使用智能位置推断")
    parser.add_argument("--force", action="store_true", help="强制应用补丁")
    
    args = parser.parse_args()
    
    if args.original and args.patch and args.output:
        # 命令行模式
        applier = PatchApplier(
            debug=args.debug,
            use_code_structure=args.code_structure,
            use_signature=args.signature,
            use_smart_position=args.smart_position,
            force_apply=args.force
        )
        
        original_content = applier.read_file(args.original)
        if not original_content:
            print(f"错误：无法读取原始文件: {args.original}")
            return
            
        patch_content = applier.read_file(args.patch)
        if not patch_content:
            print(f"错误：无法读取补丁文件: {args.patch}")
            return
            
        patches = applier.parse_patch(patch_content)
        if not patches:
            print("错误：无法解析补丁文件，格式可能不正确")
            return
            
        modified_content = original_content.copy()
        for patch in patches:
            modified_content = applier.apply_patch(modified_content, patch)
            
        applier.write_file(args.output, modified_content)
        
        print(f"补丁已成功应用到文件: {args.output}")
        
        # 比较文件
        diffs = applier.compare_files(original_content, modified_content)
        print(f"文件差异: {len(diffs)} 处")
        
    else:
        # GUI模式
        root = tk.Tk()
        app = PatchApplierGUI(root)
        
        # 配置文本标签
        app.diff_text.tag_config("add", foreground="green")
        app.diff_text.tag_config("remove", foreground="red")
        
        root.mainloop()

if __name__ == "__main__":
    main()